#pragma once

#ifndef _T2LIST_H_
#define _T2LIST_H_

#ifndef max
#define max(a,b) (a>b?a:b)
#endif

#ifndef min
#define min(a,b) (a<b?a:b)
#endif

template<class T,class D>class T2List
{
	public:
		T2List()
		{}

		virtual ~T2List()
		{}

		virtual void lock()//Only works with the T3ListProtected template!!!!
		{}

		virtual void unlock()//Only works with the T3ListProtected template!!!!
		{}

		virtual char pushFront(T newKey,D newData)
		/*
		Append a new entry to the front of the list
		Return values:
		0 - success
		1 - a node with the same key already exists
		*/
		{return 0;}

		virtual char pushBack(T newKey,D newData)
		/*
		Append a new entry to the back of the list
		Return values:
		0 - success
		1 - a node with the same key already exists
		*/
		{return 0;}

		virtual D find(T seaKey)//Returns the data assoziated with the key seaKey
		{return NULL;}

		virtual unsigned int getSize()//Returns the number of elements in the list
		{return 0;}

		virtual void clear()
		/*
		Removes all Entries from the list
		Not recommended for AVLLISTS that store pointers as data!
		*/
		{}

		virtual D at(unsigned int index)//Returns the element at position index
		{return NULL;}

		virtual T getKeyAt(unsigned int index)//Returns the key for the element at position <index>
		{return NULL;}

		virtual D getFirst()//Returns the first element in the list
		{return NULL;}

		virtual D getLast()//Returns the last element in the list
		{return NULL;}

		virtual void sort()
		/*
		Sorts the entries in the list by key (ascending).
		Not needed with avl lists, those are always sorted ascending!
		*/
		{}

		virtual void inversesort()
		/*
		Sorts the entries in the list by key (descending).
		Does not work with avl lists, those are always sorted ascending!
		Either use T2AVLListInverted as the backend or search from the back.
		*/
		{}

		virtual char removeByKey(T delKey)
		/*
		Remove the entry with key delKey
		Return values:
		0 - success
		1 - no node found with key <delKey>
		2 (AVLLIST ONLY) - tree has no root 
		*/
		{return 0;}

		virtual char removeAt(unsigned int index)
		/*
		Remove the entry at position <index>
		Return values:
		0 - success
		1 - no node found with key <delKey>
		*/
		{return 0;}

		virtual char changeKey(T oldKey, T newKey)
		/*
		Changes the key for the data associated with <oldKey> to <newKey>
		Return values:
		0 - success
		1 - node found with key <newKey>
		2 - no node found with key <oldKey>
		3 (AVLLIST ONLY) - tree has no root
		*/
		{return 0;}
};

template<class T,class D,template <class,class> class B, bool debugginEnabled, bool keepLogOpen>class T3ListProtectedBase: public B<T,D>
{
private:
	CSemaphore* listSemaphore;
public:
	T3ListProtectedBase()
	{
		//Create semaphore
		listSemaphore = new CSemaphore(1, debugginEnabled, keepLogOpen);
	}

	~T3ListProtectedBase()
	{
		//Delete semaphore
		delete listSemaphore;
	}

	void lock(void)
	{
		//Lock semaphore
		listSemaphore->lock(debugginEnabled);
	}

	void unlock(void)
	{
		//Unlock semaphore
		listSemaphore->unlock(debugginEnabled);
	}

	char pushFront(T newKey,D newData)
	/*
	Append a new entry to the front of the list
	Return values:
	0 - success
	1 - a node with the same key already exists
	*/
	{
		lock();
		char retVal=B<T,D>::pushFront(newKey,newData);
		unlock();
		return retVal;
	}

	char pushBack(T newKey,D newData)
	/*
	Append a new entry to the back of the list
	Return values:
	0 - success
	1 - a node with the same key already exists
	*/
	{
		lock();
		char retVal=B<T,D>::pushBack(newKey,newData);
		unlock();
		return retVal;
	}

	D find(T seaKey)
	{
		lock();
		D retVal=B<T,D>::find(seaKey);
		unlock();
		return retVal;
	}

	unsigned int getSize()
	{
		lock();
		unsigned int retVal=B<T,D>::getSize();
		unlock();
		return retVal;
	}

	void clear()
	/*
	Removes all Entries from the list
	Not recommended for AVLLISTS that store pointers as data!
	*/
	{
		lock();
		B<T,D>::clear();
		unlock();
	}

	T getKeyAt(unsigned int index)//Returns the key for the element at position <index>
	{
		lock();
		T retVal=B<T,D>::getKeyAt(index);
		unlock();
		return retVal;
	}

	D at(unsigned int index)
	{
		lock();
		D retVal=B<T,D>::at(index);
		unlock();
		return retVal;
	}

	D getFirst()
	{
		lock();
		D retVal=B<T,D>::getFirst();
		unlock();
		return retVal;
	}

	D getLast()
	{
		lock();
		D retVal=B<T,D>::getLast();
		unlock();
		return retVal;
	}

	void sort()
	/*
	Sorts the entries in the list by key (ascending).
	Not needed with avl lists, those are always sorted ascending!
	*/
	{
		lock();
		B<T,D>::sort();
		unlock();
	}

	void inversesort()
	/*
	Sorts the entries in the list by key (descending).
	Does not work with avl lists, those are always sorted ascending!
	Either use T2AVLListInverted as the backend or search from the back.
	*/
	{
		lock();
		B<T,D>::inversesort();
		unlock();
	}

	char removeByKey(T delKey)
	/*
	Remove the entry with key delKey
	Return values:
	0 - success
	1 - no node found with key <delKey>
	2 (AVLLIST ONLY) - tree has no root 
	*/
	{
		lock();
		char retVal=B<T,D>::removeByKey(delKey);
		unlock();
		return retVal;
	}

	char removeAt(unsigned int index)
	/*
	Remove the entry at position <index>
	Return values:
	0 - success
	1 - no node found with key <delKey>
	*/
	{
		lock();
		char retVal=B<T,D>::removeAt(index);
		unlock();
		return retVal;
	}

	char changeKey(T oldKey, T newKey)//Removes the element at position index from the list
	/*
	Changes the key for the data associated with <oldKey> to <newKey>
	Return values:
	0 - success
	1 - node found with key <newKey>
	2 - no node found with key <oldKey>
	3 - list has no root
	*/
	{
		lock();
		char retVal=B<T,D>::changeKey(oldKey, newKey);
		unlock();
		return retVal;
	}
};
#endif

template<class T,class D,template <class,class> class B>class T3ListProtected: public T3ListProtectedBase<T,D,B,false, false>
{
};

template<class T,class D,template <class,class> class B>class T3ListProtectedDebug: public T3ListProtectedBase<T,D,B,true, false>
{
};

template<class T,class D,template <class,class> class B>class T3ListProtectedDebugKeepLog: public T3ListProtectedBase<T,D,B,true, true>
{
};